﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web.Services;
using System.Web.Script.Services;

namespace ZF.BLL
{
    public class OnLine
    {
        static OnLine()
        {
            OnLineList = new List<OnLineModel>();
            ThreadPool.QueueUserWorkItem(new WaitCallback(CheckTimeOutThread));
        }
        public static List<OnLineModel> OnLineList
        {
            get;
            set;
        }
        public static void Reg(IMember member)
        {
            var olModel=OnLineList.FirstOrDefault(p=>p.Member.MemberId==member.MemberId);
            if(olModel!=null)
            {
                olModel.IsOut=false;
                olModel.IsTimeOut=false;
                Keep(member);
            }else{

                OnLineList.Add(new OnLineModel()
                {
                    IsTimeOut = false,
                    LastActiveTime = DateTime.Now,
                    IsOut = false,
                    Key = Guid.NewGuid().ToString(),
                    Member = member
                });
            }
            
        }
        public static void UnReg(IMember member)
        {
            var olModel = OnLineList.FirstOrDefault(p => p.Member.MemberId == member.MemberId);
            if (olModel != null)
            {
                olModel.IsOut = true;
                olModel.IsTimeOut = false;
                OnLineList.Remove(olModel);
            }
        }
        public static bool Keep(IMember member)
        {
            var olModel = OnLineList.FirstOrDefault(p => p.Member.MemberId == member.MemberId);
            if (olModel != null)
            {
                olModel.LastActiveTime = DateTime.Now;
                return true;
            }else
                return false;
        }
        public static void CheckTimeOutThread(object o)
        {
            while (true)
            {

                try
                {
                    OnLineList.Where(p => p.LastActiveTime.AddSeconds(60*2) < DateTime.Now)
                        .ToList().ForEach(p => p.IsTimeOut = true);
                }
                catch (Exception)
                {
                }
                Thread.Sleep(1000*50);
            }
        }
        public static bool CheckOnLine(int memberId)
        {
           return OnLineList.Exists(p => p.MemberId == memberId && !p.IsTimeOut);

        }
    }
   

    public partial class Chat
    {
        static List<OnLineModel> OnLineList { get { return OnLine.OnLineList; } }
        static Chat() { RoomList = new List<ChatRoom>(); }
        public static  List<ChatRoom> RoomList { get; set; }
        public static List<ChatRoom> CallTemp = new List<ChatRoom>();
        public static ChatRoom Call(IMember from, int toId)
        {
            string key = null;
            var olFrom = OnLineList.FirstOrDefault(p => p.MemberId == from.MemberId);
            var olTo = OnLineList.FirstOrDefault(p => p.MemberId == toId);
            if (olFrom != null && olTo != null)
            {
                var cr = RoomList.FirstOrDefault(p => p.MemberA.MemberId == from.MemberId && p.MemberB.MemberId == toId);

                if (cr == null)
                    cr = CallTemp.FirstOrDefault(p => p.MemberA.MemberId == from.MemberId && p.MemberB.MemberId == toId);
                if (cr != null)
                {
                    cr.AIsOut = false;
                    key = cr.Key;
                    cr.MemberA.Member = from;
                }
                else
                {
                    cr = new ChatRoom(olFrom, olTo) { BIsOut = false, AIsOut = false };
                    RoomList.Add(cr);
                    CallTemp.Add(cr);
                    key = cr.Key;
                }
                return cr;
            }
            else
            {
                throw new Exception("对方不在线");
            }
        }
        public static void ApplySuccess(ChatRoom cr)
        {
            cr.ApplySuccess = null;
            RoomList.Add(cr);
            
        }
        public static List<MsgModel> Rec(IMember member, string roomKey)
        {
            var rm = RoomList.FirstOrDefault(p => p.Key == roomKey);
            if (rm == null)
            {
                return new List<MsgModel>();
            }
            else
            {
                var rmsgList = rm.Rec(member);
                var msglist = rmsgList.Select(p => new MsgModel(p)).ToList();
                return msglist;
            }
        }
        [WebMethod]
        [ScriptMethod]
        public  List<MsgModel> Rec(int memberId, string roomKey)
        {
            var member = OnLineList.FirstOrDefault(p => p.MemberId == memberId);
            if (member == null)
                return new List<MsgModel>();
            else
                return Rec(member.Member,roomKey);
        }
        public static MsgModel Send(IMember member,string msg,string roomKey)
        { 
            var rm = RoomList.FirstOrDefault(p => p.Key == roomKey);
            if (rm == null)
            {
                throw new Exception();
            }
            else
            {
                return new MsgModel(rm.SendTo(member, msg));
            }
        }
        [WebMethod]
        [ScriptMethod]
        public  MsgModel Send(int memberId, string msg, string roomKey)
        {
            var member = OnLineList.FirstOrDefault(p => p.MemberId == memberId);
            if (member == null)
                return null; 
            else
                return Send(member.Member, msg, roomKey);
        }
        public static List<MsgModel> RecCall(IMember member, bool getAll)
        {
            var list = CallTemp.Where(p => p.MemberB.MemberId == member.MemberId).ToList();
            CallTemp.RemoveAll(p => list.Contains(p));
            if (getAll)
            {
                var listTemp = RoomList.Where(p => p.MemberB.MemberId == member.MemberId && !p.BIsOut).ToList();
                if (listTemp.Count > 0)
                    list.AddRange(listTemp);
            }
            return list.Select(p => new MsgModel()
            {
                RoomKey = p.Key,
                IType = 10000,
                FromMember = p.MemberA.Member.Account,
                FromMemberId = p.MemberA.MemberId,
            }).ToList();
        }
        [WebMethod]
        [ScriptMethod]
        public List<MsgModel> RecCall(int memberId,bool getAll)
        {
            var member = OnLineList.FirstOrDefault(p => p.MemberId == memberId);
            if (member == null)
                return new List<MsgModel>();
            else

                return RecCall(member.Member, getAll);
        }
        [WebMethod]
        [ScriptMethod]
        public  bool Keep(int memberId)
        {
            var member = OnLineList.FirstOrDefault(p => p.MemberId == memberId);
            if (member == null)
                return false;
            else
               return  OnLine.Keep(member.Member);
        }
        [WebMethod]
        [ScriptMethod]
        public bool Out(int memberId,string roomKey)
        {
            var member = OnLineList.FirstOrDefault(p => p.MemberId == memberId);

            var r = GetChatRoom(roomKey);
            if (r == null)
                return false;
            else
            {
                var result = r.Out(member.Member);
                if (result && r.AIsOut && r.BIsOut)
                {
                    RoomList.Remove(r);
                    CallTemp.Remove(r);
                }
                return result;
            }
 
        }
        [WebMethod]
        [ScriptMethod]
        public bool ApplyBilling(string roomKey)
        {
            var r = GetChatRoom(roomKey);
            if (r == null)
                return false;
            else
               return r.ApplyBilling();
        }
        [WebMethod]
        [ScriptMethod]
        public bool ApplyBack(string roomKey,bool result)
        {
            var r = GetChatRoom(roomKey);
            if (r == null)
                return false;
            else
                return r.ApplyBack(result);
        }
        [WebMethod]
        [ScriptMethod]
        public bool ApplyStop(string roomKey)
        {
            var r = GetChatRoom(roomKey);
            if (r == null)
                return false;
            else
                return r.ApplyStop();
        }
        public static ChatRoom GetChatRoom(string roomKey)
        {
            var r = RoomList.FirstOrDefault(p => p.Key == roomKey);
            if (r == null)
            {
                r = CallTemp.FirstOrDefault(p => p.Key == roomKey);
            }
            return r;
        }
        [WebMethod]
        [ScriptMethod]
        public bool SetInte(string roomKey, int inte)
        {
            var r = GetChatRoom(roomKey);
            if (r == null)
                return false;
            else
            {
                r.InteSet = inte;
                return true;
            }
        }
        [WebMethod]
        [ScriptMethod]
        public int GetInte(string roomKey)
        {
            var r = GetChatRoom(roomKey);
            if (r == null)
                return 0;
            else
            {
                return r.InteSet;
            }
        }
    }

    public class ChatRoom
    {
      
        public  Action<ChatRoom> ApplySuccess;
        public ChatRoom(OnLineModel a, OnLineModel b)
        {
            Key = Guid.NewGuid().ToString();
            MemberA = a;
            MemberB = b;
            AllMsgList = new List<RoomMsg>();
            NRMsgList = new List<RoomMsg>();
            using (var dc = SiteInfo.CreateDBDataContext())
            {
                var member = dc.US_Member.FirstOrDefault(p => p.MemberId == b.MemberId);
                this.InteSet = member.InteSet;
            }
        }
        public int InteSet { get; set; }//积分计数
        public string Key { get; set; }
        /// <summary>
        /// 主动者(发起人)
        /// </summary>
        public OnLineModel MemberA { get; set; }
        /// <summary>
        /// 被动者（专家)
        /// </summary>
        public OnLineModel MemberB { get; set; }
        public bool AIsOut { get; set; }
        public bool BIsOut { get; set; }
        public List<RoomMsg> AllMsgList { get; set; }
        /// <summary>
        /// 未接收消息
        /// </summary>
        public List<RoomMsg> NRMsgList { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="oper">发送人</param>
        /// <param name="msg"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public RoomMsg SendTo(IMember oper, string msg, MsgType type)
        {
            OnLineModel from = null;
            OnLineModel to = null;
            if (MemberA.Member.MemberId == oper.MemberId)
            {
                from = MemberA;
                to = MemberB;
            }
            else
            {
                from = MemberB;
                to = MemberA;
            }
            RoomMsg rm = rm = new RoomMsg()
            {
                From = from,
                To = to,
                Key = Guid.NewGuid().ToString(),
                Msg = msg,
                Order = DateTime.Now.ToFileTime(),
                Status = 1,
                RoomKey=this.Key,
            };
            
            if (type == MsgType.msg)
            {
                if (!AIsOut && !BIsOut && !from.IsTimeOut && !to.IsTimeOut)
                {
                    rm.Type = type;
                    AllMsgList.Insert(0, rm);
                    NRMsgList.Add(rm);
                }
                else
                {
                    if (from == MemberA)
                    {
                        if (AIsOut)
                            rm.Type = MsgType.isout;
                        else if (MemberA.IsOut || MemberA.IsTimeOut)
                            rm.Type = MsgType.isto;
                        else if (BIsOut)
                            rm.Type = MsgType.osout;
                        else if (MemberB.IsOut || MemberB.IsTimeOut)
                            rm.Type = MsgType.osto;
                    }
                    else
                    {
                        if (BIsOut)
                            rm.Type = MsgType.isout;
                        else if (MemberB.IsOut || MemberB.IsTimeOut)
                            rm.Type = MsgType.isto;
                        else if (AIsOut)
                            rm.Type = MsgType.osout;
                        else if (MemberA.IsOut || MemberA.IsTimeOut)
                            rm.Type = MsgType.osto;
                    }

                    switch (rm.Type)
                    {
                        case MsgType.isout:
                            rm.Msg = string.Format("您已退出当前会话，刚才发送的<br/>{0}无效", rm.Msg);
                            break;
                        case MsgType.isto:
                            rm.Msg = string.Format("您已退出登录，刚才发送的<br/>{0}无效", rm.Msg);
                            break;
                        case MsgType.osout:
                            rm.Msg = string.Format("对方已退出当前会话，您刚才发送的<br/>{0}对方未能接收", rm.Msg);
                            break;
                        case MsgType.osto:
                            rm.Msg = string.Format("对方已退出登录，您刚才发送的<br/>{0}对方未能接收", rm.Msg);
                            break;

                    }
                     
                   
                }
            }
            else
            {
                rm.Type = type;
                NRMsgList.Add(rm);
            }
            
            return rm;
            
        }
        public RoomMsg SendTo(IMember oper, string msg)
        {
            return SendTo(oper, msg, MsgType.msg);
        }
        /// <summary>
        /// 是否计费中
        /// </summary>
        public bool IsBilling { get; set; }
        /// <summary>
        /// 是否申请计费中
        /// </summary>
        public bool IsApplyBilling { get; set; }

        public bool Out(IMember oper)
        {
            if (oper.MemberId == MemberA.MemberId)
            {
                if (!AIsOut)
                {
                    //SendTo(MemberA.Member, "对方已退出对话", MsgType.osout);
                    AIsOut = true;
                }
                return true;
            }
            else if (oper.MemberId == MemberB.MemberId)
            {
                if (!BIsOut)
                {
                    //SendTo(MemberB.Member, "对方已退出对话", MsgType.osout);
                    BIsOut = true;
                }
                return true;
            }
            else
                return false;
        } 
        public List<RoomMsg> Rec(IMember oper)
        {
            var msgList = NRMsgList.Where(p => p.To.Member.MemberId == oper.MemberId).ToList();
            msgList.ForEach(p => p.Status = 2);
            NRMsgList.RemoveAll(p => msgList.Contains(p));
            return msgList;
        }
        public class RoomMsg
        {
            public OnLineModel From { get; set; }
            public OnLineModel To { get; set; }
            public long Order { get; set; }
            public string Msg { get; set; }
            public MsgType Type { get; set; }
            public string Key { get; set; }
            public string RoomKey{get;set;}
            /// <summary>
            /// 1已发送，未接收
            /// 2已接收
            /// </summary>
            public int Status {get;set;}
        }
        public enum MsgType
        {
            /// <summary>
            /// 正常消息
            /// </summary>
            msg=1,
            /// <summary>
            /// 对方掉线
            /// </summary>
            osto=10,//对方掉线
            /// <summary>
            /// 我掉线
            /// </summary>
            isto=11,//我掉线
            /// <summary>
            /// 对方退出
            /// </summary>
            osout=20,//对方退出
            /// <summary>
            /// 我退出
            /// </summary>
            isout=21,//我退出


            /// <summary>
            /// 申请计费
            /// </summary>
            ApplyBilling = 50,//申请计费
            /// <summary>
            /// 确认计费失败
            /// </summary>
            ApplyFail = 51,//确认计费失败
            /// <summary>
            /// 确认计费成功
            /// </summary>
            ApplySuccess = 52,//确认计费成功
            /// <summary>
            /// 计费停止 
            /// </summary>
            ApplyStop = 53,//计费停止 
            /// <summary>
            /// 计费信息
            /// </summary>
            BillingInfo=54,
        }
         
        public bool ApplyBack(bool result)
        {
            if (IsApplyBilling && !IsBilling && !AIsOut && !BIsOut && !MemberA.IsTimeOut &&
                    !MemberB.IsTimeOut && !MemberA.IsOut && !MemberA.IsOut)
            {
                if (result)
                {
                    IsBilling = true;
                    SendTo(MemberA.Member, "对方已允许你的计费咨询申请", MsgType.ApplySuccess);
                    SendTo(MemberB.Member, "你已允许对方的计费咨询申请", MsgType.ApplySuccess);
                    ThreadPool.QueueUserWorkItem(new WaitCallback(BillingThread));
                }
                else
                {
                    IsBilling = false;
                    SendTo(MemberA.Member, "对方拒绝你的计费咨询申请", MsgType.ApplyFail);
                    SendTo(MemberB.Member, "你已拒绝对方计费咨询申请", MsgType.ApplyFail);
                }

                IsApplyBilling = false;
                return true;
            }
            else
            {
                if (result)
                    return false;
                else
                    return true;
            }
        }
        public bool ApplyBilling()
        {
            if (!IsApplyBilling && !IsBilling && !AIsOut && !BIsOut && !MemberA.IsTimeOut &&
                    !MemberB.IsTimeOut && !MemberA.IsOut && !MemberA.IsOut)
            {
                IsApplyBilling = true;
                SendTo(MemberB.Member, "对方申请与你进行计费咨询，是否确认", MsgType.ApplyBilling);
                SendTo(MemberA.Member, "正在申请与对方进行计费咨询，等待对方确认", MsgType.ApplyBilling);
                return true;
            }
            else
                return false;
        }
        public bool ApplyStop()
        {
            IsBilling = false;
            IsApplyBilling = false;
            return true;
        }
        public DateTime LastBillingTime { get; set; }
        /// <summary>
        /// 计费线程
        /// </summary>
        void BillingThread(object o)
        {

            Action stop = () =>
                {
                    SendTo(MemberB.Member, "计费咨询已停止", MsgType.ApplyStop);
                    SendTo(MemberA.Member, "计费咨询已停止", MsgType.ApplyStop);
                    IsBilling = false;
                };

            while (true)
            {
                if (!IsApplyBilling)
                {
                    if (IsBilling && !AIsOut && !BIsOut && !MemberA.IsTimeOut &&
                        !MemberB.IsTimeOut && !MemberA.IsOut && !MemberA.IsOut)
                    {

                        if (LastBillingTime.AddSeconds(10 * (SiteInfo.Instance.IsLocal ? 1 : 6)) <= DateTime.Now)
                        {

                            using (var ts = new System.Transactions.TransactionScope())
                            {
                                using (var dc = SiteInfo.CreateDBDataContext())
                                {
                                    var integra = InteSet;
                                    var ma = dc.US_Member.FirstOrDefault(p => p.MemberId == this.MemberA.MemberId);
                                    var mb = dc.US_Member.FirstOrDefault(p => p.MemberId == this.MemberB.MemberId);
                                    if (ma==null ||mb == null)
                                    {
                                        stop();
                                        return;
                                    }

                                    if (ma.Integral < integra)
                                    {
                                        SendTo(MemberB.Member, "你的积分已不够本次计费咨询扣费，计费咨询自动停止", MsgType.ApplyStop);
                                        SendTo(MemberA.Member, "对方的积分已不够本次计费咨询扣费，计费咨询自动停止.", MsgType.ApplyStop);
                                        IsBilling = false;
                                        return;
                                        
                                    }
                          
                                    ma.Integral = ma.Integral - integra;
                                    dc.US_IntegralLog.InsertOnSubmit(new ZF.Model.US_IntegralLog()
                                    {
                                        MemberId = ma.MemberId,
                                        Title = "在线咨询计时扣分",
                                        Integral = integra,
                                        AddTime = DateTime.Now,
                                    });
                                    MemberA.Member.Integral = ma.Integral;

                                    mb.Integral += integra;
                                    dc.US_IntegralLog.InsertOnSubmit(new ZF.Model.US_IntegralLog()
                                    {
                                        MemberId = mb.MemberId,
                                        Title = "在线计费咨询得分",
                                        Integral = -integra,
                                        AddTime = DateTime.Now,
                                    });
                                    MemberB.Member.Integral = mb.Integral;
                                    dc.SubmitChanges();
                                    ts.Complete();
                                    SendTo(MemberB.Member, ma.Integral.ToString(), MsgType.BillingInfo);
                                    SendTo(MemberA.Member, mb.Integral.ToString(), MsgType.BillingInfo);
                                }
                            }




                            LastBillingTime = DateTime.Now;
                            

                        }
                    }
                    else
                    {

                        stop();
                        IsBilling = false;
                        return;
                        
                    }
                }
                Thread.Sleep(1 * 1000);
            }
        }
        
    }
    public class OnLineModel
    {
        public int MemberId { get { return Member.MemberId; } }
        public IMember Member { get; set; }
        public string Key { get; set; }
        public DateTime LastActiveTime { get; set; }
        public bool IsTimeOut { get; set; }
        public bool IsOut { get; set; }
        public void SendMsg(string msg, int type)
        {
        }
        
    }
    public class MsgModel
    {
        public MsgModel()
        {
        }
        public MsgModel(ZF.BLL.ChatRoom.RoomMsg msg)
        {
            FromMemberId = msg.From.MemberId;
            FromMember = msg.From.Member.Account;
            ToMember = msg.To.Member.Account;
            ToMemberId = msg.To.MemberId;
            this.Status = msg.Status;
            this.IType = (int)msg.Type;
            this.SType = msg.Type.ToString();
            this.MsgKey = msg.Key;
            this.RoomKey = msg.RoomKey;
            this.Msg = msg.Msg; ;
        }
        public int FromMemberId { get; set; }
        public int ToMemberId { get; set; }
        public string FromMember { get; set; }
        public string ToMember { get; set; }
        public string Msg { get; set; }
        /// <summary>
        /// 10已接收,20未接收
        /// </summary>
        public int Status { get; set; }
        /// <summary>
        /// 10000为call
        /// </summary>
        public int IType { get; set; }
        public string SType { get; set; }
        public string MsgKey { get; set; }
        public string RoomKey { get; set; }
        public int Order { get; set; }

    }



}
